package tests.fakes;

import jeconbond.automata.INode;
import jeconbond.automata.IOutcome;
import jeconbond.automata.Node;
import jeconbond.automata.Outcome;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.resources.ResourceBasket;
import jeconbond.economic.resources.ResourceStorrage;

public class GenerateCycleAutomata {
	private static interface ICreator {
		public IOutcome newOut(IResourceType resource, double cost, INode node);
	}
	
	private static class CustomerCreator implements ICreator {
		public IOutcome newOut(IResourceType resource, double cost, INode node) {
			return new Outcome(node, new ResourceBasket(resource, cost));
		}
	}

	private static class ProdCreator implements ICreator {
		public IOutcome newOut(IResourceType resource, double cost, INode node) {
			Outcome out = new Outcome(node);
			out.setProducedResources(new ResourceBasket(resource, cost * 2.0));
			return out;
		}
	}
	
	private static INode generate(IResourceType[] resources, double[] costs, ICreator outCreator) {
		int n = costs.length;
		if (n != resources.length) {
			return null;
		}
		INode root = new Node("n0");
		INode prev = root;
		for (int i = 0; i < n; i++) {
			INode node;
			if (i < n - 1) {
				node = new Node("n" + (i+1));
			} else {
				node = root;
			}
			IOutcome out = outCreator.newOut(resources[i], costs[i], node); 
			prev.getOutcomes().add(out);
			prev = node;
		}
		return root;
	}

	public static INode generateCustomer(
			IResourceType[] resources, 
			double ... costs
	) {
		return generate(resources, costs, new CustomerCreator());
	}

	public static INode generateProducer(
			IResourceType[] resources, 
			double ... costs
	) {
		return generate(resources, costs, new ProdCreator());
	}

	public static ResourceStorrage usePerDayStorr(INode root) {
		ResourceStorrage result = new ResourceStorrage();
		INode node = root;
		while (true) {
			for (ResourceBasket rb : node.getOutcomes().get(0).getRequirements()) {
				result.storeResource(rb);
			}
			node = node.getOutcomes().get(0).getDestination();
			if (node == root) {
				break;
			}
		}
		return result;
	}
	
	public static ResourceStorrage prodPerDayStorr(INode root) {
		ResourceStorrage result = new ResourceStorrage();
		INode node = root;
		while (true) {
			for (ResourceBasket rb : node.getOutcomes().get(0).getProducedResources()) {
				result.storeResource(rb);
			}
			node = node.getOutcomes().get(0).getDestination();
			if (node == root) {
				break;
			}
		}
		return result;
	}

	public static void storeInitials(
			IResourceType[] resources,
			ResourceStorrage storrage,
			double mult,
			double ... costs
	) {
		storrage.clear();
		int n = costs.length;
		for (int i = 0; i < n; i++) {
			storrage.storeResource(resources[i], costs[i] * mult);
		}
	}
}
